<template>
  <a-card title="楼房分户" style="width: 600px;pointer-events: all;">
    <template #extra>
      <UndoOutlined @click="refresh" />
    </template>
    <a-steps :current="currentStep" :items="steps">
    </a-steps>
    <div class="draw-area">
      <span>绘制户型:</span>
      <ForkOutlined class="icon-draw" @click="activeDraw" />
      <span>{{ textDraw }}</span>
    </div>
    <div class="form-area">
      <a-table size="small" bordered :data-source="buildingData" :columns="buildingColumns" :pagination="false">
        <template #bodyCell="{ column, text, record }">
          <template v-if="['posPrefix', 'unit'].includes(column.dataIndex)">
            <div>
              <a-input v-if="editableData[record.key]" v-model:value="editableData[record.key][column.dataIndex]"
                style="margin: -5px 0" />
              <template v-else>
                {{ text }}
              </template>
            </div>
          </template>

          <!-- 只有做区域绘制的时候，需要编辑 -->
          <template v-else-if="column.dataIndex === 'operation' && currentStep !== 2">
            <div class="editable-row-operations">
              <span v-if="editableData[record.key]" style="display: flex;justify-content: space-around;">
                <a-typography-link @click="save(record.key)">保存</a-typography-link>
                <a-popconfirm title="Sure to cancel?" @confirm="cancel(record.key)">
                  <a>取消</a>
                </a-popconfirm>
              </span>
              <span v-else>
                <a @click="edit(record.key)">编辑</a>
              </span>
            </div>
          </template>

          <!-- 只有户型切分的时候，需要定位 -->
          <template v-if="['positionFix'].includes(column.dataIndex)">
            <div @click="focusOnArea(record.key)">
              <img style="cursor: pointer;" width="20" height="20" src="/src/assets/position.png" alt="">
            </div>
          </template>
        </template>

      </a-table>
    </div>
    <!-- 楼房分层 -->
    <div class="floor-area" v-if="currentStep === 2 && showDivide">
      <span>最低点:</span>
      <a-input width="100" :value="minHeight" :min="-100" :max="200" :disabled="true"></a-input>
      <span>分割点:</span>
      <a-input width="100" :value="divideHeight" :min="-100" :max="200" :disabled="true"></a-input>
      <span>最高点:</span>
      <a-input width="100" :value="maxHeight" :min="-100" :max="200" :disabled="true"></a-input>
      <span>楼层数:</span>
      <a-input width="100" v-model:value="floorNum" :min="0" :max="100"></a-input>
    </div>
    <div class="button-area">
      <a-button v-if="currentStep < steps.length - 1" type="primary" @click="nextStep">下一步</a-button>
      <a-button v-if="showDivide" @click="divideFloor" style="margin:0 10px;">楼房分层</a-button>
      <a-button v-if="currentStep == steps.length - 1 && updateActive" type="primary" @click="updateInfo">
        生成数据
      </a-button>
    </div>
  </a-card>
</template>

<script setup>
import * as Cesium from 'cesium'
import { ref, reactive, computed, watch, onBeforeUnmount } from 'vue';
import { cloneDeep } from 'lodash'
import { binkEntityMaterial } from '@/cesiumTools/sceneManager.js'
import { changeCartesin3ToGeoJson, polygonCut, cartesian3ToDegreesHeight } from '@/cesiumTools/utils'
import DrawTool from '../cesiumTools/drawTool'
import { UndoOutlined, ForkOutlined } from '@ant-design/icons-vue'
import { useMapData } from '@/store'
import { addHouse } from '@/api/api'
import { message } from 'ant-design-vue';

const mapStore = useMapData()
// 获取到cesium地图对象viewer
const viewer = mapStore.Viewer
const drawTool = new DrawTool(viewer)
// 当前进行到的步骤
const currentStep = ref(0)
// 是否能够展示分层按钮，只有在点击了三个楼层高度之后才能展示分层按钮
const showDivide = ref(false)
// 是否能够点击上传数据，只有所有数据都准备好之后才能点击上传
const updateActive = ref(false)
// 楼房的三个高度
const minHeight = ref(0)
const divideHeight = ref(0)
const maxHeight = ref(0)
// 楼层数
const floorNum = ref(0)

// 推送到服务端的数据
// polygonJson总区域geojson字符串
// polygonJsonArr切割后geojson字符串数组，如果没有切割，传[]
// unitArr 单位数组
// heightArr 三个高度数组
// name 楼栋名称
// floorNum楼层数
let postDataSource = {
  polygonJson: '',
  polygonJsonArr: [],
  unitArr: [],
  heightArr: [],
  name: '',
  floorNum: 0
}
// 户型设置 表格数据
const buildingData = ref([])
const buildingColumns = ref([{
  title: '分户坐标',
  dataIndex: 'position',
  align: 'center',
  width: '30%',
  ellipsis: true
}, {
  title: '地址前缀',
  dataIndex: 'posPrefix',
  align: 'center',
  width: '30%',
  ellipsis: true
}, {
  title: '单位',
  dataIndex: 'unit',
  align: 'center'
}, {
  title: '操作',
  dataIndex: 'operation',
  align: 'center'
}])

const steps = ref([
  {
    title: '区域绘制',
    key: '区域绘制'
  }, {
    title: '户型切分',
    key: '户型切分'
  }, {
    title: '楼房分层',
    key: '楼房分层'
  }
])

watch(currentStep, (val) => {
  if (val === 0) {
    if (!buildingColumns.value.find(item => item.dataIndex === 'operation')) {
      buildingColumns.value.push({
        title: '操作',
        dataIndex: 'operation',
        align: 'center'
      })
    }
  }
  if (val === 1) {
    if (!buildingColumns.value.find(item => item.dataIndex === 'positionFix')) {
      buildingColumns.value.push({
        title: '定位',
        dataIndex: 'positionFix',
        align: 'center',
        width: '10%'
      })
    }
  }
  // 楼房分层，将后面两列删除
  if (val === 2) {
    buildingColumns.value = buildingColumns.value.filter(item => item.dataIndex !== 'positionFix' && item.dataIndex !== 'operation')
  }
})

const editableData = reactive({});
// 可编辑表格配置
const edit = key => {
  editableData[key] = cloneDeep(buildingData.value.filter(item => key === item.key)[0]);
};
const save = key => {
  Object.assign(buildingData.value.filter(item => key === item.key)[0], editableData[key]);
  delete editableData[key];
};
const cancel = key => {
  delete editableData[key];
};

const textDraw = computed(() => {
  let res = ''
  switch (currentStep.value) {
    case 0:
      res = '绘制图形'
      break;
    case 1:
      res = '户型裁剪'
      break;
    case 2:
      res = '楼层分层'
      break;
    default:
      break;
  }
  return res
})

// 刷新到初始状态
const refresh = () => {
  if (buildPrimitives.length) {
    buildPrimitives.forEach(p => {
      viewer.scene.primitives.remove(p)
    })
    buildPrimitives = []
  }
  viewer.entities.removeAll()
  currentStep.value = 0
  postDataSource = {
    polygonJson: '',
    polygonJsonArr: [],
    unitArr: [],
    heightArr: [],
    name: '',
    floorNum: 0
  }
  updateActive.value=false
  showDivide.value=false
  buildingData.value=[]
  drawEndEvent && drawTool.removeListener(drawEndEvent)
  drawTool.removeAllDrawEnts()
}

// 下一步点击
const nextStep = () => {
  if (buildingData.value.length) {
    currentStep.value++
  } else {
    message.warn('请先绘制区域')
  }
}

const focusOnArea = (key) => {
  ;
  const targetEntity = viewer.entities.values.find(item => item.name === key)
  if (targetEntity) {
    binkEntityMaterial(targetEntity)
  }
}

const updateInfo = async () => {
  postDataSource.unitArr = buildingData.value.map(item => Number(item.unit))
  postDataSource.heightArr = [minHeight.value, divideHeight.value, maxHeight.value]
  postDataSource.name = buildingData.value[0].posPrefix
  postDataSource.floorNum = Number(floorNum.value)
  console.log(postDataSource,'postDataSource')
  const res = await addHouse(postDataSource)
  if (res.code === 200) {
    message.success('分户成功')
    refresh()
  }else{
    message.error('分户失败')
  }
}

let buildPrimitives = []
// 楼房分层逻辑
const divideFloor = () => {
  if (floorNum.value > 1) {
    const itemHeight = (maxHeight.value - divideHeight.value) / (floorNum.value - 1)
    viewer.entities.removeAll()
    buildingData.value.forEach(item => {
      const { position } = item
      const positionArr = position.split(',').map(item => Number(item))
      const cartesian = new Cesium.Cartesian3.fromDegreesArray(positionArr)
      const hierachy = new Cesium.PolygonHierarchy(cartesian)
      for (let i = 0; i < floorNum.value; i++) {
        let height, extrudedHeight
        if (i === 0) {
          height = minHeight.value
          extrudedHeight = divideHeight.value
        } else {
          height = divideHeight.value + (i - 1) * itemHeight
          extrudedHeight = divideHeight.value + (i) * itemHeight
        }

        const geometryInstance = new Cesium.GeometryInstance({
          geometry: new Cesium.PolygonGeometry({
            polygonHierarchy: hierachy,
            height,
            extrudedHeight,
          }),
          // 这里务必把颜色写在instance中，因为每一户的颜色都不一样，所以不能用appearance来指定颜色
          attributes: {
          // ColorGeometryInstanceAttribute 对象，包含：
          //{
          //   componentDatatype: Cesium.ComponentDatatype.UNSIGNED_BYTE,
          //   componentsPerAttribute: 4, // RGBA
          //   normalize: true,           // 归一化到 0-1 范围
          //   value: [108, 192, 59, 76]  // 对应的 RGBA 整数值
          // }
            color: Cesium.ColorGeometryInstanceAttribute.fromColor(
              Cesium.Color.fromRandom({ alpha: 0.3 }) //颜色
            ),
          }
        })

        const p = new Cesium.ClassificationPrimitive({
          geometryInstances: geometryInstance,
          classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
        })
        viewer.scene.primitives.add(p)
        buildPrimitives.push(p)
      }
    })

    // 将上传服务的按钮打开
    updateActive.value = true
  }
}


let polygonGeo
let drawEndEvent
let lastDrawEnt
const activeDraw = () => {
  // 步骤1 绘制楼栋区域
  if (currentStep.value === 0) {
    drawTool.active(drawTool.DrawTypes.Polygon)
    drawEndEvent = (ent, positions) => {
      // 把positions坐标转geojson
      const { geojson, positionLng } = changeCartesin3ToGeoJson(positions, 'polygon')
      if (geojson) {
        lastDrawEnt = ent
        polygonGeo = geojson
        // 填充表格数据
        buildingData.value[0] = {
          position: positionLng.join(','),
          posPrefix: 'xxx小区xxx楼栋',
          unit: '1'
        }

        postDataSource.polygonJson = JSON.stringify(geojson.geometry)
      }
      // 每次绘制完了之后将绘制结束事件的监听结束
      drawEndEvent && drawTool.removeListener(drawEndEvent)
    }
    drawTool.DrawEndEvent.addEventListener(drawEndEvent)
  } else if (currentStep.value === 1) {
    // 步骤2  绘制楼栋单元，激活线段绘制工具
    drawTool.active(drawTool.DrawTypes.Polyline)
    drawEndEvent = (ent, positions) => {
      // 调用polygonCut将上一步的区域裁剪为多个多边形
      if (polygonGeo) {
        const { geojson: lineJson } = changeCartesin3ToGeoJson(positions, 'polyline')
        const featureCollection = polygonCut(polygonGeo, lineJson)

        if (featureCollection) {
          lastDrawEnt && viewer.entities.remove(lastDrawEnt)
          drawTool.removeAllDrawEnts()
          // 加载这个多边形集合的geojson数据---渲染
          // 将多边形的数据加载到表格，并且加载到postDataSource中
          postDataSource.polygonJsonArr = featureCollection.features.map(item => {
            return JSON.stringify(item.geometry)
          })
          new Cesium.GeoJsonDataSource().load(featureCollection, { clampToGround: true }).then(dataSource => {
            let tableData = []
            dataSource.entities.values.forEach((item, index) => {
              item.polygon.material = new Cesium.Color.fromRandom({ alpha: 0.5 })
              item.name = index
              tableData.push({
                key: index,
                position: featureCollection.features[index].geometry.coordinates.toString(),
                posPrefix: buildingData.value[0].posPrefix,
                unit: index + 1
              })
              viewer.entities.add(item)
            })
            buildingData.value = tableData
          })
        }
      }
      drawEndEvent && drawTool.removeListener(drawEndEvent)
    }
    drawTool.DrawEndEvent.addEventListener(drawEndEvent)
  } else if (currentStep.value === 2) {
    // 步骤3：激活点绘制工具，点选出底层，二楼，顶楼三个位置的高度
    drawTool.active(drawTool.DrawTypes.Point)
    drawEndEvent = (ent, positions) => {
      if (positions.length !== 3) {
        message.warn('请绘制底层，二楼，顶楼三个位置的高度')
        return
      }
      // 得到三个位置的高
      const heightArr = positions.map(position => {
        const positionLng = cartesian3ToDegreesHeight(position)
        return positionLng[2]
      }).sort((a, b) => a - b)

      minHeight.value = heightArr[0]
      divideHeight.value = heightArr[1]
      maxHeight.value = heightArr[2]
      // 打开分层按钮
      showDivide.value = true

      // 每次绘制完了之后将绘制结束事件的监听结束
      drawEndEvent && drawTool.removeListener(drawEndEvent)
    }
    drawTool.DrawEndEvent.addEventListener(drawEndEvent)
  }
}
</script>

<style scoped>
.button-area {
  display: flex;
  justify-content: flex-end;
  margin-top: 20px;
}

.draw-area {
  margin: 20px 0;
}

.draw-area span {
  margin: 0 4px;
}

.icon-draw {
  padding: 4px;
}

.icon-draw:hover {
  cursor: pointer;
  background-color: skyblue;
  color: #fff;
}

.floor-area span {
  margin: 0 10px;
}
</style>